﻿// Principia
// Copyright (C) 2008 Blake Hegerle
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;

namespace Principia.Core.Parsing.ContextFree
{
    public interface INonterminal : ISymbol
    {
        IEnumerable<Production> Productions { get; }
    }

    public class Nonterminal<S> : ISymbol<S>, INonterminal
    {
        private readonly List<Production> productions;

        public Nonterminal(string Name)
        {
            this.Name = Name;
            productions = new List<Production>();
        }

        #region ISymbol Members
        public string Name { get; set; }
        public int Id { get; set; }
        #endregion

        #region INonterminal Members
        public IEnumerable<Production> Productions
        {
            get { return productions; }
        }
        #endregion

        public Production add(Func<S> SemanticFunc)
        {
            return add(new Production {Head = this, SemanticFunc = SemanticFunc, Symbols = new ISymbol[0]});
        }

        public Production add<R>(ISymbol<R> r1)
            where R : S
        {
            return add(r1, v => v);
        }

        public Production add<R1>(ISymbol<R1> r1, Func<R1, S> SemanticFunc)
        {
            return add(new Production {Head = this, SemanticFunc = SemanticFunc, Symbols = new ISymbol[] {r1}});
        }

        public Production add<R1, R2>(ISymbol<R1> r1, ISymbol<R2> r2, Func<R1, R2, S> SemanticFunc)
        {
            return add(new Production {Head = this, SemanticFunc = SemanticFunc, Symbols = new ISymbol[] {r1, r2}});
        }

        public Production add<R1, R2, R3>(ISymbol<R1> r1, ISymbol<R2> r2, ISymbol<R3> r3, Func<R1, R2, R3, S> SemanticFunc)
        {
            return add(new Production {Head = this, SemanticFunc = SemanticFunc, Symbols = new ISymbol[] {r1, r2, r3}});
        }

        public Production add<R1, R2, R3, R4>(ISymbol<R1> r1, ISymbol<R2> r2, ISymbol<R3> r3, ISymbol<R4> r4,
                                              Func<R1, R2, R3, R4, S> SemanticFunc)
        {
            return
                add(new Production {Head = this, SemanticFunc = SemanticFunc, Symbols = new ISymbol[] {r1, r2, r3, r4}});
        }

        public Production add<R1, R2, R3, R4, R5>(ISymbol<R1> r1, ISymbol<R2> r2, ISymbol<R3> r3, ISymbol<R4> r4,
                                                  ISymbol<R5> r5, Func<R1, R2, R3, R4, R5, S> SemanticFunc)
        {
            return
                add(new Production
                    {Head = this, SemanticFunc = SemanticFunc, Symbols = new ISymbol[] {r1, r2, r3, r4, r5}});
        }

        public Production add<R1, R2, R3, R4, R5, R6>(ISymbol<R1> r1, ISymbol<R2> r2, ISymbol<R3> r3, ISymbol<R4> r4,
                                                      ISymbol<R5> r5, ISymbol<R6> r6,
                                                      Func<R1, R2, R3, R4, R5, R6, S> SemanticFunc)
        {
            return
                add(new Production
                    {Head = this, SemanticFunc = SemanticFunc, Symbols = new ISymbol[] {r1, r2, r3, r4, r5, r6}});
        }

        public Production add<R1, R2, R3, R4, R5, R6, R7>(ISymbol<R1> r1, ISymbol<R2> r2, ISymbol<R3> r3, ISymbol<R4> r4,
                                                          ISymbol<R5> r5, ISymbol<R6> r6, ISymbol<R7> r7,
                                                          Func<R1, R2, R3, R4, R5, R6, R7, S> SemanticFunc)
        {
            return
                add(new Production
                    {Head = this, SemanticFunc = SemanticFunc, Symbols = new ISymbol[] {r1, r2, r3, r4, r5, r6, r7}});
        }

        //public Production add<R1, R2, R3, R4, R5, R6, R7, R8>(ISymbol<R1> r1, ISymbol<R2> r2, ISymbol<R3> r3, ISymbol<R4> r4,
        //                                                      ISymbol<R5> r5, ISymbol<R6> r6, ISymbol<R7> r7, ISymbol<R8> r8,
        //                                                      Func<R1, R2, R3, R4, R5, R6, R7, R8, S> SemanticFunc)
        //{
        //    return
        //        add(new Production
        //            {Head = this, SemanticFunc = SemanticFunc, Symbols = new ISymbol[] {r1, r2, r3, r4, r5, r6, r7, r8}});
        //}

        //public Production add<R1, R2, R3, R4, R5, R6, R7, R8, R9>(ISymbol<R1> r1, ISymbol<R2> r2, ISymbol<R3> r3,
        //                                                          ISymbol<R4> r4, ISymbol<R5> r5, ISymbol<R6> r6,
        //                                                          ISymbol<R7> r7, ISymbol<R8> r8, ISymbol<R9> r9,
        //                                                          Func<R1, R2, R3, R4, R5, R6, R7, R8, R9, S>
        //                                                              SemanticFunc)
        //{
        //    return
        //        add(new Production
        //            {
        //                Head = this,
        //                SemanticFunc = SemanticFunc,
        //                Symbols = new ISymbol[] {r1, r2, r3, r4, r5, r6, r7, r8, r9}
        //            });
        //}

        //public Production add<R1, R2, R3, R4, R5, R6, R7, R8, R9, R10>(ISymbol<R1> r1, ISymbol<R2> r2, ISymbol<R3> r3,
        //                                                               ISymbol<R4> r4, ISymbol<R5> r5, ISymbol<R6> r6,
        //                                                               ISymbol<R7> r7, ISymbol<R8> r8, ISymbol<R9> r9,
        //                                                               ISymbol<R10> r10,
        //                                                               Func<R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, S>
        //                                                                   SemanticFunc)
        //{
        //    return
        //        add(new Production
        //            {
        //                Head = this,
        //                SemanticFunc = SemanticFunc,
        //                Symbols = new ISymbol[] {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10}
        //            });
        //}

        //public Production add<R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11>(ISymbol<R1> r1, ISymbol<R2> r2, ISymbol<R3> r3,
        //                                                                    ISymbol<R4> r4, ISymbol<R5> r5, ISymbol<R6> r6,
        //                                                                    ISymbol<R7> r7, ISymbol<R8> r8, ISymbol<R9> r9,
        //                                                                    ISymbol<R10> r10, ISymbol<R11> r11,
        //                                                                    Func
        //                                                                        <R1, R2, R3, R4, R5, R6, R7, R8, R9, R10
        //                                                                        , R11, S> SemanticFunc)
        //{
        //    return
        //        add(new Production
        //            {
        //                Head = this,
        //                SemanticFunc = SemanticFunc,
        //                Symbols = new ISymbol[] {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11}
        //            });
        //}

        //public Production add<R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12>
        //    (ISymbol<R1> r1, ISymbol<R2> r2, ISymbol<R3> r3, ISymbol<R4> r4, ISymbol<R5> r5, ISymbol<R6> r6, ISymbol<R7> r7,
        //     ISymbol<R8> r8, ISymbol<R9> r9, ISymbol<R10> r10, ISymbol<R11> r11, ISymbol<R12> r12,
        //     Func<R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, S> SemanticFunc)
        //{
        //    return
        //        add(new Production
        //            {
        //                Head = this,
        //                SemanticFunc = SemanticFunc,
        //                Symbols = new ISymbol[] {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12}
        //            });
        //}

        //public Production add<R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13>
        //    (ISymbol<R1> r1, ISymbol<R2> r2, ISymbol<R3> r3, ISymbol<R4> r4, ISymbol<R5> r5, ISymbol<R6> r6, ISymbol<R7> r7,
        //     ISymbol<R8> r8, ISymbol<R9> r9, ISymbol<R10> r10, ISymbol<R11> r11, ISymbol<R12> r12, ISymbol<R13> r13,
        //     Func<R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, S> SemanticFunc)
        //{
        //    return
        //        add(new Production
        //            {
        //                Head = this,
        //                SemanticFunc = SemanticFunc,
        //                Symbols = new ISymbol[] {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13}
        //            });
        //}

        //public Production add<R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14>
        //    (ISymbol<R1> r1, ISymbol<R2> r2, ISymbol<R3> r3, ISymbol<R4> r4, ISymbol<R5> r5, ISymbol<R6> r6, ISymbol<R7> r7,
        //     ISymbol<R8> r8, ISymbol<R9> r9, ISymbol<R10> r10, ISymbol<R11> r11, ISymbol<R12> r12, ISymbol<R13> r13,
        //     ISymbol<R14> r14, Func<R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, S> SemanticFunc)
        //{
        //    return
        //        add(new Production
        //            {
        //                Head = this,
        //                SemanticFunc = SemanticFunc,
        //                Symbols = new ISymbol[] {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14}
        //            });
        //}

        //public Production add<R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15>
        //    (ISymbol<R1> r1, ISymbol<R2> r2, ISymbol<R3> r3, ISymbol<R4> r4, ISymbol<R5> r5, ISymbol<R6> r6, ISymbol<R7> r7,
        //     ISymbol<R8> r8, ISymbol<R9> r9, ISymbol<R10> r10, ISymbol<R11> r11, ISymbol<R12> r12, ISymbol<R13> r13,
        //     ISymbol<R14> r14, ISymbol<R15> r15,
        //     Func<R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, S> SemanticFunc)
        //{
        //    return
        //        add(new Production
        //            {
        //                Head = this,
        //                SemanticFunc = SemanticFunc,
        //                Symbols = new ISymbol[] {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15}
        //            });
        //}

        //public Production add<R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16>
        //    (ISymbol<R1> r1, ISymbol<R2> r2, ISymbol<R3> r3, ISymbol<R4> r4, ISymbol<R5> r5, ISymbol<R6> r6, ISymbol<R7> r7,
        //     ISymbol<R8> r8, ISymbol<R9> r9, ISymbol<R10> r10, ISymbol<R11> r11, ISymbol<R12> r12, ISymbol<R13> r13,
        //     ISymbol<R14> r14, ISymbol<R15> r15, ISymbol<R16> r16,
        //     Func<R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, S> SemanticFunc)
        //{
        //    return
        //        add(new Production
        //            {
        //                Head = this,
        //                SemanticFunc = SemanticFunc,
        //                Symbols = new ISymbol[] {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16}
        //            });
        //}

        //public Production add<R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17>
        //    (ISymbol<R1> r1, ISymbol<R2> r2, ISymbol<R3> r3, ISymbol<R4> r4, ISymbol<R5> r5, ISymbol<R6> r6, ISymbol<R7> r7,
        //     ISymbol<R8> r8, ISymbol<R9> r9, ISymbol<R10> r10, ISymbol<R11> r11, ISymbol<R12> r12, ISymbol<R13> r13,
        //     ISymbol<R14> r14, ISymbol<R15> r15, ISymbol<R16> r16, ISymbol<R17> r17,
        //     Func<R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17, S> SemanticFunc)
        //{
        //    return
        //        add(new Production
        //            {
        //                Head = this,
        //                SemanticFunc = SemanticFunc,
        //                Symbols =
        //                    new ISymbol[] {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17}
        //            });
        //}

        //public Production add<R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17, R18>(
        //    ISymbol<R1> r1, ISymbol<R2> r2, ISymbol<R3> r3, ISymbol<R4> r4, ISymbol<R5> r5, ISymbol<R6> r6, ISymbol<R7> r7,
        //    ISymbol<R8> r8, ISymbol<R9> r9, ISymbol<R10> r10, ISymbol<R11> r11, ISymbol<R12> r12, ISymbol<R13> r13,
        //    ISymbol<R14> r14, ISymbol<R15> r15, ISymbol<R16> r16, ISymbol<R17> r17, ISymbol<R18> r18,
        //    Func<R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17, R18, S> SemanticFunc)
        //{
        //    return
        //        add(new Production
        //            {
        //                Head = this,
        //                SemanticFunc = SemanticFunc,
        //                Symbols =
        //                    new ISymbol[]
        //                    {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18}
        //            });
        //}

        //public Production add<R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17, R18, R19>(
        //    ISymbol<R1> r1, ISymbol<R2> r2, ISymbol<R3> r3, ISymbol<R4> r4, ISymbol<R5> r5, ISymbol<R6> r6, ISymbol<R7> r7,
        //    ISymbol<R8> r8, ISymbol<R9> r9, ISymbol<R10> r10, ISymbol<R11> r11, ISymbol<R12> r12, ISymbol<R13> r13,
        //    ISymbol<R14> r14, ISymbol<R15> r15, ISymbol<R16> r16, ISymbol<R17> r17, ISymbol<R18> r18, ISymbol<R19> r19,
        //    Func<R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17, R18, R19, S> SemanticFunc)
        //{
        //    return
        //        add(new Production
        //            {
        //                Head = this,
        //                SemanticFunc = SemanticFunc,
        //                Symbols =
        //                    new ISymbol[]
        //                    {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19}
        //            });
        //}

        public Production add(Delegate Delegate, params ISymbol[] Symbols)
        {
            return add(new Production {Head = this, SemanticFunc = Delegate, Symbols = Symbols});
        }

        private Production add(Production Production)
        {
            productions.Add(Production);
            return Production;
        }
    }
}